params provides dynamic route parameters (e.g., /products/[id]), while searchParams provides URL query string values. Both can be used in Server Components, but searchParams opts the page into dynamic rendering.
In Next.js page components, params and searchParams serve distinct purposes. params contains the dynamic route parameters defined by folder names in square brackets (like [slug]), while searchParams contains the URL's query string parameters (the part after ? in the URL). Both are available as props to page components in the App Router, and crucially, both can be used in Server Components—but with an important caveat: using searchParams opts the page into dynamic rendering at request time because query strings cannot be known at build time [citation:2][citation:6].
Source: params comes from the URL path structure defined by folder names in square brackets [citation:4]; searchParams comes from the URL query string after the ? [citation:2].
Type structure: params has a fixed shape based on your route structure (e.g., { slug: string } for [slug] routes, or { slug: string[] } for catch-all [...slug] routes) [citation:2][citation:4]; searchParams is a flexible object where keys can be strings, arrays (for repeated parameters), or undefined [citation:2][citation:6].
Rendering impact: params alone does not affect rendering mode—pages can be statically generated with known params values via generateStaticParams [citation:4]; searchParams is a Dynamic API that forces the page to use dynamic rendering because query strings cannot be known at build time [citation:2][citation:6][citation:9].
Availability: Both are available only in page components (the leaf of the route tree). Layouts do not receive searchParams to prevent stale values during navigation [citation:3][citation:5].
Yes, both params and searchParams can be used in Server Components—specifically in page components, which are Server Components by default [citation:2]. However, there are important distinctions. params is perfectly compatible with static generation: you can use generateStaticParams to pre-render pages for all known parameter combinations at build time [citation:4]. For example, an e-commerce site can pre-render all product pages by generating params for each product ID. searchParams, in contrast, forces dynamic rendering because its values cannot be known until request time—they depend on how the user interacts with the page [citation:2][citation:6][citation:9]. This trade-off is intentional: Next.js optimizes for static generation by default but gives you access to dynamic data when needed.
A significant change in Next.js 15 is that both params and searchParams are now Promises that must be awaited [citation:2][citation:9]. This change enables advanced patterns like streaming and partial rendering. In practice, this means you must use async/await or React's use() function to access the values. The official documentation emphasizes this breaking change: in version 14 and earlier, these props were synchronous, but in version 15, they are Promises (with a codemod available for migration) [citation:2]. This applies to both Server Components (using await) and Client Components (using React's use hook) [citation:2][citation:8].
Layouts and searchParams: Layouts do not receive searchParams as a prop. This is intentional—layouts are not re-rendered during navigation, so they would show stale query parameters [citation:3]. If a layout needs search params, you must read them in the page and pass them down, or use useSearchParams() in a Client Component [citation:3][citation:5].
Prop drilling challenge: For deeply nested Server Components, params and searchParams must be passed explicitly through props. There is no built-in way for arbitrary Server Components to access these values directly [citation:5][citation:7]. This has led to community solutions like @sodefa/next-server-context that use AsyncLocalStorage to share context [citation:7].
Type safety: You can use the globally available PageProps helper to get strongly typed params and searchParams from a route literal, e.g., PageProps<'/blog/[slug]'> [citation:2][citation:9].
Multiple values: If the same query parameter appears multiple times (e.g., ?tag=react&tag=nextjs), searchParams will represent it as an array: { tag: ['react', 'nextjs'] } [citation:2][citation:6].
For Client Components, Next.js provides the useSearchParams hook as an alternative to receiving searchParams as a prop [citation:3]. However, this hook has an important behavior: if used without a Suspense boundary in a statically rendered page, it will cause the component tree up to the nearest Suspense boundary to be client-side rendered, preserving the static shell while the dynamic part hydrates on the client [citation:3][citation:8]. The Next.js documentation strongly recommends wrapping components that use useSearchParams in a Suspense boundary to avoid fully client-side rendering [citation:8]. This pattern gives you the best of both worlds: a static shell with dynamic client-side hydration for the interactive parts that depend on query parameters.